<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>深入理解原型链</title>
    <style>
      section {
        width: 1000px;
        margin: 0px auto;
      }
    </style>
  </head>
  <body>
    <section>
      <h3>原型链图解</h3>
      <img src="./原型链 图解.jpg" alt="原型链图解" srcset="" />
    </section>

    <script>
      // 函数也是对象:对象分为函数对象和普通对象
      // 对象和对象的创建
      var o1 = {};
      var o2 = new Object();
      var o3 = new f1();
      var o4 = Object.create({});

      // 函数和函数的创建
      function f1() {}
      var f2 = new Function();
      var f3 = function() {};

      console.log("o1", typeof o1); //object
      console.log("o2", typeof o2); //object
      console.log("o3", typeof o3); //object
      console.log("o4", typeof o4); //object
      console.log("f1", typeof f1); //function
      console.log("f2", typeof f2); //function
      console.log("f3", typeof f3); //function
      console.log("Function", typeof Function); //function
      console.log("Object", typeof Object); //function

      // 普通对象都是由构造函数创建，普通对象在创建的时候带有constructor 和 __proto__ 属性
      // constructor 是一个指向其构造函数的指针
      // __proto__  是一个指向构造函数原型对象的指针

      console.log("o1.constructor", o1.constructor); //ƒ Object() { [native code] }
      console.log("o2.constructor", o2.constructor); //ƒ Object() { [native code] }
      console.log("o3.constructor", o3.constructor); //ƒ f1() {}

      console.log("o1.prototype", o1.prototype); //undefined
      console.log("o2.prototype", o2.prototype); //undefined
      console.log("o3.prototype", o3.prototype); //undefined

      console.log("o1.__proto__", o1.__proto__ === Object.prototype); // true
      console.log("o2.__proto__", o2.__proto__ === Object.prototype); //true
      console.log("o3.__proto__", o3.__proto__ === f1.prototype); //true

      // 构造函数在创建的时候也是带有constructor  __proto__ 属性 ，并且比普通对象多一个 prototype 属性
      // 构造函数的constructor指针都是指向 Function
      // 构造函数的__proto__指针都是指向 一个匿名函数

      console.log("f1.constructor", f1.constructor); //ƒ Function() { [native code] }
      console.log("f2.constructor", f2.constructor); //ƒ Function() { [native code] }
      console.log("f3.constructor", f3.constructor); //ƒ Function() { [native code] }

      console.log("f1.prototype", f1.prototype); //{constructor：f f1(),__proto__:Object}
      console.log("f2.prototype", f2.prototype); //{constructor：f anonymous(),__proto__:Object}
      console.log("f3.prototype", f3.prototype); //{constructor：f (),__proto__:Object}

      console.log("f1.__proto__", f1.__proto__); // ƒ () { [native code] }
      console.log("f2.__proto__", f2.__proto__); //ƒ () { [native code] }
      console.log("f3.__proto__", f3.__proto__); //ƒ () { [native code] }

      // 所以在Function的原型其实是一个匿名函数
      console.log("Function.prototype", Function.prototype); //ƒ () { [native code] }
      // 那么Function作为构造函数其 constructor 和  __proto__ 分别指向哪里呢？
      console.log("Function.constructor", Function.constructor); // ƒ Function() { [native code] }
      console.log("Function.__proto__", Function.__proto__); //ƒ () { [native code] }
      // 可以看到 Function 的构造函数是自己 ，原型对象是匿名函数

      // 那么这个匿名函数有没有 constructor __proto__ prototype 三个属性呢？又分别指向哪里呢
      console.log(
        "Function.__proto__.constructor",
        Function.__proto__.constructor
      ); // ƒ Function() { [native code] }
      console.log("Function.__proto__.prototype", Function.__proto__.prototype); // undefined
      console.log(
        "Function.__proto__.__proto__",
        Function.__proto__.__proto__ === Object.prototype
      ); // true
      //  Function.__proto__ 是一个匿名函数 ，其是一个特殊的对象，没有prototype属性，
      // 和普通对象一样只有 constructor 和 __proto__ 指针
      // 我们可以得出这个特殊的匿名函数的__proto__指向是对象的原型

      // 这个对象的原型是否还存在指针，其指向是哪里呢？
      console.log("Object.prototype.constructor", Object.prototype.constructor); // ƒ Object() { [native code] }
      console.log("Object.prototype.__proto__", Object.prototype.__proto__); // null
      console.log("Object.prototype.prototype", Object.prototype.prototype); // undefined

      console.log("o4.__proto__", o4.__proto__); // {}
      console.log("o4.prototype", o4.prototype); // undefined
      console.log("o4.constructor", o4.constructor); // ƒ Object() { [native code] }

      // objectA instaceof objectB : instanceof 运算符用来检测 constructor.prototype 是否存在于参数 object 的原型链上。
      //  return  objectA.__proto__ === objectB.prototype
      console.log("o1 instanceof Object", o1 instanceof Object); // true
      console.log("o1 instanceof Function", o1 instanceof Function); // false
      console.log("f1 instanceof Object", o1 instanceof Object); // true
      console.log("f1 instanceof Function", o1 instanceof Function); // false
      console.log("Object instanceof Function", Object instanceof Function); // true
      console.log("Function instanceof Object", Function instanceof Object); // true

      // 需要注意的是：objectA.__proto__ === objectB.prototype 并不是永远成立，当objectB的prototype的指向改变的时候，则不成立。
      function C() {}
      var c = new C();
      var d = {};
      console.log("c instanceof C", c instanceof C);
      C.prototype = d;
      console.log("c instanceof C", c instanceof C);
      // console.log("c instanceof d",c instanceof d)  // Uncaught TypeError: Right-hand side of 'instanceof' is not callable
      var e = new C();
      console.log("e.__proto__", e.__proto__); // {}
    </script>
  </body>
</html>
